# -*- coding:utf-8 -*-
import requests
import json
import base64
import time
import math
import hashlib
import os,pathlib
import uuid
import pandas as pd
import argparse
import yaml


# URL = "http://117.132.181.235:9050"  # 推理网关的地址
# # URL = "http://172.31.184.162:30800"  # 推理网关的地址
# # URL = "http://127.0.0.1:8000"
# TDEV = 0  # 测试机器与北京时间的偏差（慢多少毫秒）

# Path = "/me/infer"  # 对应“API管理”中的“PATH映射”
# # Path = "/ability/v1/sys_quality/online/test"
# APPID = "facemerd"  # 对应“授权管理”中的“应用标识”
# APPKey = "e742a8648ab3804530a902d26bf11200"  # 对应“授权管理”中的“应用秘钥”
# request_video_name_list = "./request_video_names.txt"


# 适配推理网关协议的头部构造方法
def create_header(Path, APPID, APPKey, TDEV=0):
    appid = APPID
    appKey = APPKey
    uid = str(uuid.uuid4())
    suid = ''.join(uid.split('-'))
    appName = Path.split('/')[1]
    for i in range(24 - len(appName)):
        appName += "0"
    capabilityname = appName
    # print(len(capabilityname))
    csid = appid + capabilityname + suid
    tmp_xServerParam = {
        "appid": appid,
        "csid": csid
    }
    # print(tmp_xServerParam)
    xCurTime = str(int(math.floor(time.time())) + TDEV)
    # print(xCurTime)
    xServerParam = str(base64.b64encode(json.dumps(
        tmp_xServerParam).encode('utf-8')), encoding="utf8")
    # xServerParam = str(base64.b64encode(json.dumps(tmp_xServerParam).encode('utf-8')))

    # turn to bytes
    xCheckSum = hashlib.md5(
        bytes(appKey + xCurTime + xServerParam, encoding="utf8")).hexdigest()
    # xCheckSum = hashlib.md5(bytes(appKey + xCurTime + xServerParam)).hexdigest()

    header = {
        # "appKey": appKey,
        "X-Server-Param": xServerParam,
        "X-CurTime": xCurTime,
        "X-CheckSum": xCheckSum,
        'Content-Type': 'application/json'
    }

    return header

# body = {
#     "video_name": "sub03@EP09_03.avi"
# }

# print(URL + Path)
# res = result = requests.post(URL + Path, data=json.dumps(body), headers=create_header())
# print("返回状态码：\t" + str(res.status_code))
# # print("返回头部: \t", res.headers)
# print(res.text.encode('utf-8').decode('unicode_escape'))

def parser_user_args():
    """读取用户的脚本输入参数"""
    parser = argparse.ArgumentParser("人脸面部微表情统一AI平台镜像评估脚本")
    parser.add_argument("--url",
                        type=str,
                        default="http://117.132.181.235:9050",
                        help="统一AI平台的推理平台URL,默认值为:http://117.132.181.235:9050")
    parser.add_argument("--path",
                        type=str,
                        default="/fmer/infer",
                        help="API网关的PATH, 默认值为:/fmer/infer")
    parser.add_argument("--appid",
                        type=str,
                        default="fmerclas",
                        help="授权应用的APPID, 默认值为: fmerclas")
    parser.add_argument("--appkey",
                        type=str,
                        default="dfdb7d1ff33555488c4b6ca14edcad0e",
                        help="授权应用的APPKEY, 默认值为: dfdb7d1ff33555488c4b6ca14edcad0e")
    parser.add_argument("--tdev",
                        type=int,
                        default=0,
                        help="测试机器与北京时间的偏差（慢多少毫秒), 默认值为: 0")
    parser.add_argument("--gt_file",
                        type=str,
                        default="./request_video.yaml",
                        help="已经上传到统一AI平台持久化卷中的测试用的视频文件的GT数据, 默认值为: ./request_video.yaml")
    parser.add_argument("--out_file",
                        type=str,
                        default="./test_requests.csv",
                        help="测试结果保存的csv文件路径, 默认值为: ./test_requests.csv")
    
    return parser.parse_args()

def send_request(video_name, video_info, args, try_num=5):
    """执行统一AI平台请求"""
    request_body = {"video_name": video_name,
                    "start_id": video_info['start_id'],
                    "end_id": video_info["end_id"]}
    # 构造请求的header()
    header = create_header(args.path, args.appid, args.appkey, args.tdev)
    while try_num > 0:
        try:
            response = requests.post(args.url+args.path, data=json.dumps(request_body), 
                                    headers=header, timeout=1000)
            try_num = 0
            if response.status_code != requests.codes.ok: # 请求成功但是服务器失败
                # print(response.content)
                text = response.text.encode('utf-8').decode('unicode_escape')
                # return None, None
                return False, None, str(response.status_code)+"-"+text
            
            # response_data_str = response.text.encode('utf-8').decode('unicode_escape')
            response_data_str = response.text
            # print(response_data_str)
            response_data = json.loads(response_data_str)
            # print(response_data)
            return True, response_data, None
            
        except requests.exceptions.ConnectionError as ex:
            if try_num <= 0:
                print("Failed to retrieve: " + args.url + args.path + "\n" + str(ex))
                return False, None, "错误信息: 无法连接服务器"
            else:
                print("连接失败，剩余尝试次数:{}".format(try_num))
                try_num -= 1
                time.sleep(0.5)


def main():
    # 读取用户的输入参数
    args = parser_user_args()
    
    # 读取已经上传的视频文件列表
    assert args.gt_file != None, "当前未指定上传的视频列表文件!"
    assert os.path.exists(args.gt_file), "指定的上传的视频列表文件不存在"
    try:
        f = open(args.gt_file, 'r')
        request_videos = yaml.load(f, Loader=yaml.SafeLoader)
        f.close()
    except:
        print(f"{args.gt_file}文件读取失败")
    
    # 开始执行请求
    test_results = []
    failed_videos = [] #测试失败的视频
    all_videos = 0
    request_success_videos = 0
    request_true_videos = 0

    print("-"*100)
    print("开始测试...")
    print("配置参数:")
    print(f"\tURL:{args.url}")
    print(f"\tPath:{args.path}")
    print(f"\tAppID:{args.appid}")
    print(f"\tAppKey:{args.appkey}")
    print(f"\tGT测试集数据:{args.gt_file}")
    print(f"\t测试结果输出:{args.out_file}")
    for video_name, item in request_videos.items():
        all_videos += 1
        print(f"\r正在测试{video_name}, 当前正在测试第{all_videos}个视频，共{len(list(request_videos.keys()))}个视频", end="", flush=True)
        res, response_data, error_text = send_request(video_name, item, args)
        if not res:
            failed_videos.append(f"{video_name}:{error_text}")
            continue
        _data = response_data['data']
        if _data is None:
            failed_videos.append(f"{video_name}:{error_text}")
            continue
        # 如果只是一个请求，不进入统计环节
        if len(list(request_videos.keys())) == 1:
            print(" ")
            if len(failed_videos) > 0:
                print(f"{video_name}测试失败，失败原因:{error_text}")
            else:
                print(f"{video_name}测试返回结果为:")
                print(json.dumps(response_data))
            print("-"*100)
            break
        start_id = item['start_id']
        end_id = item['end_id']
        gt_8s_label = item['8s_label_name']
        gt_4s_id = item['4s_id']
        pred_4s_id = _data['action']['class_id']
        prob_4s_id = _data['action']['probability']
        pred_4s_label = _data['action']['class']
        pred_emotion =_data['most_emotion']
        # pred_emotion = "emotion"
        test_results.append([video_name,
                            start_id,
                            end_id,
                            gt_8s_label,
                            gt_4s_id,
                            pred_4s_id,
                            prob_4s_id,
                            pred_4s_label,
                            pred_emotion])
        request_success_videos += 1
        if gt_4s_id == pred_4s_id:
            request_true_videos += 1
        
        # 测试发现如果请求的太快的话容易出现543错误
        time.sleep(1)

    
    # 如果是一个测试的话，提前退出
    if len(list(request_videos.keys())) == 1:
        return None

    # 将测试结果保存下来
    test_results_pd = pd.DataFrame(test_results,
                                columns=["视频文件", 
                                        "微表情开始帧",
                                        "微表情结束帧",
                                        "8分类的微表情GT标签",
                                        "4分类的微表情GT ID",
                                        "4分类微表情预测ID",
                                        "4分类预测概率",
                                        "预测ID对应的4分类微表情标签",
                                        "视频情绪"])
    test_results_pd.to_csv(args.out_file, index=False)

    # print("-"*100)
    print("测试结果为:")
    print("\t共测试{}个文件, 请求成功{}个, 失败{}个".format(all_videos,
                    request_success_videos,
                    all_videos - request_success_videos))
    print("\t其中{}个文件与GT结果一直，模型的识别的准确率(UAR)为 {:.2f}%".format(
                request_true_videos, 
                100*(request_true_videos/request_success_videos)))
    if len(failed_videos)>0:
        print(f"测试失败的视频文件为:{failed_videos}")
    print("-"*100)

if __name__ == "__main__":
    main()
